<div id="adversaries" class="section-profile">
  <div class="row">
    <div class="bottomright duk-icon"><img onclick="toggleSidebar('adversaries-sidebar')" src="/gui/img/expand.png"></div>
    <div class="topleft duk-icon"><img onclick="removeSection('adversaries')" src="/gui/img/x.png"></div>
    <div id="adversaries-sidebar" class="column section-border" style="flex:25%;">
      <img src="/gui/img/hacker.png">
      <h4>Adversary Profiles</h4>
      <br>
      <div class="toggle">
        <label class="switch"><input type="checkbox" id="togBtnAdv" onchange="toggleAdversaryView()">
          <div class="slider round"><span class="on">ADD</span><span class="off">VIEW</span></div>
        </label>
      </div>
      <p class="section-description">
          Adversary Profiles are collections of ATT&CK TTPs, designed to create specific effects on a host or network.
          Profiles
          can be used for offensive or defensive use cases.
      </p>
      <div id="adversary-view" class="adversary-sidebar-option">
        <select id="profile-existing-name" onchange="loadAdversary();">
          <option value="" disabled selected>Select an existing profile</option>
          {% for adv in adversaries %}
              <option id="adversary-{{ adv.adversary_id}}" value="{{ adv.adversary_id }}">{{ adv.name }}</option>
          {% endfor %}}
        </select>
      </div>
      <button id="adversary-save-button" type="button" class="button-notready atomic-button" onclick="saveAdversary()">Save</button>
      <hr>
      <button id="adversary-delete-button" type="button" class="button-notready atomic-button" onclick="deleteProfile()">Delete</button>

      <div id="adversary-add" class="adversary-sidebar-option">

      </div>
    </div>
    <div id="adversary-content" class="column adversary-header">
        <div id="row">
            <input id="profile-goal" type="text" placeholder="enter a profile name (required)" oninput="checkAdversaryButtons()">
            <img id='objective-img' style="display:none" src="/gui/img/compass.png" onclick="showObjectiveModal()">
        </div>
        <input id="objective-select" type="text" style="display:none" disabled>
        <input id="profile-description" type="text" placeholder="enter a profile description (required)" oninput="checkAdversaryButtons()">
        <br><br>
        <div id="dummy"></div>
    </div>
  </div>
</div>

<div id="phase-modal" class="modal">
    <form class="modal-content">
        <div class="container section-profile row ability-viewer modal-box">
            <div class="column">
                <select id="ability-tactic-filter" onchange="populateTechniques('phase-modal', exploits);">
                    <option disabled selected>Choose a tactic</option>
                    {% for tactic in tactics %}
                        <option value={{ tactic }} data-tactic={{ tactic }}>{{ tactic }}</option>
                    {% endfor %}}
                </select>
                <select id="ability-technique-filter" onchange="populateAbilities('phase-modal', exploits);">
                    <option disabled selected>Choose a technique</option>
                </select>
                <select id="ability-ability-filter" onchange="showAbility('phase-modal', exploits)">
                    <option disabled selected>0 abilities</option>
                </select>
                <input id="ability-search-filter" type="text" placeholder="Search for abilities..." oninput="searchAbilities('phase-modal', exploits);">
                <button id="reset-ability-modal-button" type="button" class="atomic-button" onclick="clearPhaseModal()">Reset Fields</button>
                <br><br>
                <div id="ability-manager" class="ability-attack row-simple">
                    <div id="ability-manager-fields" class="column">
                        <table frame=void rules=rows>
                            <tr>
                                <td>id:</td>
                                <td><input type="text" id="ability-identifier" placeholder="Unique identifier (default UUID)" oninput="checkAbilityButtons()" /></td>
                            </tr>
                            <tr>
                                <td>name:</td>
                                <td><input type="text" id="ability-name" placeholder="Name (required)" oninput="checkAbilityButtons()" /></td>
                            </tr>
                            <tr>
                                <td>description:</td>
                                <td><input type="text" id="ability-description" placeholder="Description (required)" oninput="checkAbilityButtons()" /></td>
                            </tr>
                            <tr>
                                <td>tactic:</td>
                                <td><input type="text" id="ability-tactic-name" placeholder="ATT&CK tactic (required)" oninput="checkAbilityButtons()" /></td>
                            <tr>
                            <tr>
                                <td>technique id:</td>
                                <td><input type="text" id="ability-tech-id" placeholder="ATT&CK technique ID" /></td>
                            </tr>
                            <tr>
                                <td>technique:</td>
                                <td><input type="text" id="ability-tech-name" placeholder="ATT&CK technique name" /></td>
                            </tr>
                        </table>

                    </div>
                    <div id="ability-manager-additional" class="column">
                        <div id="row-simple">
                            <div class="column">
                                <div>
                                    <img onclick="freshId()" src="/gui/img/recycle.png">
                                    <p onclick="freshId()">generate new id</p>
                                </div>
                            </div>
                            <div class="column">
                                <div>
                                    <img onclick="addExecutorBlock()" src="/gui/img/executor.png">
                                    <p onclick="addExecutorBlock()">add executor</p>
                                </div>
                            </div>
                            <div class="column">
                                <div>
                                    <label for="uploadPayloadFile"><img src="/gui/img/payload.png"></label>
                                    <form id="uploadPayloadForm">
                                       <label id="uploadFileLabel" for="uploadPayloadFile"><br><br>upload payload</label>
                                       <input type="file" id="uploadPayloadFile" style="display: none">
                                    </form>
                                </div>
                            </div>
                            <div class="column">
                                <div>
                                    <img onclick="addAdditionalInfo(); checkAbilityButtons()" src="/gui/img/additional-fields.png">
                                    <p onclick="addAdditionalInfo(); checkAbilityButtons()">add info</p>
                                </div>
                            </div>
                        </div>
                        <div id="ability-additional-info" style="display: none">
                            <div>info:</div>
                            <table id="additional-info-table" frame=void rules=rows>
                                <tbody>
                                </tbody>
                            </table>
                        </div>
                    </div>
                    <br><br>
                </div>
                <div id="ability-button-row" class="row-simple">
                    <button id="ability-save" type="button" class="button-notready atomic-button" onclick="saveAbility()">Save</button>
                    <button id="ability-add-to-adv" type="button" class="button-notready atomic-button" onclick="saveAbility(true)">Add to Adversary</button>
                </div>
                <div class="row-simple">
                    <ul id="ttp-tests"></ul>
                </div>
            </div>
            <div class="imgcontainer">
                <span onclick="hidePhaseModal()" class="close" title="Close Modal">&times;</span>
            </div>
        </div>
    </form>
</div>

<div id="phase-template" style="display: none;">
    <center>
        <div class="grid" id="grid">
        </div>
    </center>
</div>

<div id="ability-template" class="ability-box" style="display: none">
    <div class="ability-show">
        <h4 id="name" style="margin:5px; margin-top:5px;"><span></span></h4>
        <b><p id="ability-attack" style="text-transform: uppercase;font-size:11px;opacity:0.7;"></p></b>
    </div>
    <center>
        <div>
            <div class="topright" id="ability-rm">
                <div class="ability-remove"><div style="font-size:8px;">&#x274C;</div></div>
            </div>
            <div class="topleftnum">
                <div class="ability-order">*</div>
            </div>
            <div id="ability-metadata" class="bottomright">
            </div>
            <div id="icon-row" class="icon-row"></div>
        </div>
    </center>
</div>

<span id="ability-tooltip" class="tooltiptext"></span>

<div id="adv-objective-modal" class="modal">
    <form class="modal-content">
        <div class="container section-profile row ability-viewer modal-box">
            <div class="column" style="flex:100%;">
                <p style="text-align: center;">Specify an objective for this adversary.</p>
                 <select id="objective-existing">
                    <option value="" disabled selected>Select an Objective</option>
                        {% for obj in objectives %}
                            <option id="objective-{{ obj.id }}" value="{{ obj.id }}">{{ obj.name }}</option>
                        {% endfor %}}
                 </select>
                <br><br>
                <hr> <br>
                <input id="objective-description" type="text" placeholder="Select an Objective" disabled>
                <div style="width:30%;margin:0 auto;">
                    <button type="button" class="button-success atomic-button"
                            onclick="linkObjective()">Link to adversary</button>
                </div>
            </div>
            <div class="imgcontainer">
                <span onclick="hideObjectiveModal()" class="close" title="Close Modal">&times;</span>
            </div>
        </div>
    </form>
</div>

<div id="adv-profile-modal" class="modal">
    <form class="modal-content">
        <div class="container section-profile row ability-viewer modal-box">
            <div class="column" style="flex:100%;">
                <p style="text-align: center;">Include the abilities of another profile in this one. These abilities can be appended to the existing adversary profile.
                </p>
                <select id="adv-profile-filter">
                    <option disabled selected>Choose a profile</option>
                    {% for adv in adversaries %}
                        <option value={{ adv.adversary_id }}>{{ adv.name }}</option>
                    {% endfor %}}
                </select>
                <br><br>
                <div style="width:30%;margin:0 auto;">
                    <button type="button" class="button-success atomic-button" onclick="addAdvToCurrentProfile()">Add to adversary</button>
                </div>
            </div>
            <div class="imgcontainer">
                <span onclick="hideProfileModal()" class="close" title="Close Modal">&times;</span>
            </div>
        </div>
    </form>
</div>


<table id="additional-info-row-template-holder" style="display:none">
    <tr id="additional-info-template">
        <td><input type="text" class="additional-key" style="text-align: right; margin-left: -2px; padding-right: 22px;" placeholder="key" oninput="checkAbilityButtons()"></td>
        <td><b>:</b></td>
        <td><input type="text" class="additional-value" placeholder="value"></td>
        <td><div class="ability-remove">
            <div style="font-size:8px;">&#x274C;</div>
        </div></td>
    </tr>
</table>

<li id="ttp-template" class="ttp-template" style="display: none">
    <div class="dotted">
        <p onclick="$(this).closest('li').remove(); checkAbilityButtons()">&#x274C;</p>
    </div>
    <table frame=void rules=rows style="border-spacing:5px;width:100%">
        <tr>
            <td style="width:10%"><b>platform:</b></td>
            <td>
              <select id="ability-platform" onchange="filterExecutors(this); checkAbilityButtons()">
                <option value="" disabled selected>Select a platform</option>
                    {% for platform, executors in platforms.items() %}
                        <option value="{{ platform }}">{{ platform }}</option>
                    {% endfor %}
              </select>
            </td>
        </tr>
        <tr>
            <td style="width:10%"><b>executor:</b></td>
            <td>
              <select id="ability-executor" onchange="checkAbilityButtons()">
                <option value="" disabled selected>Select an executor</option>
              </select>
            </td>
        </tr>
        <tr>
            <td style="width:10%"><b>payloads:</b></td>
            <td>
              <select id="ability-payload" multiple="multiple">
                {% for p in payloads|sort %}
                    <option value="{{ p }}">{{ p }}</option>
                {% endfor %}}
              </select>
            </td>
        </tr>
        <tr>
            <td style="width:10%"><b>command:</b></td>
            <td><textarea id="ability-command" spellcheck="false" contenteditable="true" placeholder="Enter a command to execute" oninput="checkAbilityButtons()"></textarea></td>
        </tr>
        <tr>
            <td style="width:10%"><b>timeout:</b></td>
            <td><input id="ability-timeout" spellcheck="false" contenteditable="true" placeholder="Enter number of seconds to timeout this command (optional)"/></td>
        </tr>
        <tr>
            <td style="width:10%"><b>cleanup:</b></td>
            <td><textarea id="ability-cleanup" spellcheck="false" contenteditable="true" placeholder="Enter a clean up command (optional)"></textarea></td>
        </tr>
    </table>
    <br>
</li>

<script src="/gui/js/ability.js"></script>
<script src="/gui/js/muuri.min.js"></script>
<script>
    var exploits = {{exploits | tojson}};
    var platforms = {{platforms | tojson}};

    $(document).ready(function () {
        stream('Profiles are optional. There are built-in profiles you can use right away, otherwise modify or build new ones here.');
        addPhase(1);
    });

    $(document).on("mouseover", ".tooltip", function(event) {
        $("#ability-tooltip").show();
        $("#ability-tooltip").css({left: event.clientX + 10, top: event.pageY, 'z-index':100});
        $("#ability-tooltip").html(this.dataset.text);
    })

    $(document).on("mouseout", ".tooltip", function(event) {
        $("#ability-tooltip").hide();
    })

    $(document).on("mouseover", ".ability-box h4", function() {
        if (isEllipsisActive(this)) {
            $(this.firstElementChild).addClass("ability-long-name");
            $(this).css("overflow", "visible");
            let abilityBox = $(this).closest(".ability-box");
            abilityBox.css("z-index", 100);
            abilityBox.find(".topleftnum, .topright").css("z-index", -1);
        }
    })

    $(document).on("mouseout", ".ability-box h4", function() {
        $(this.firstElementChild).removeClass("ability-long-name");
        $(this).css("overflow", "hidden");
        let abilityBox = $(this).closest(".ability-box");
        abilityBox.css("z-index", 1);
        abilityBox.find(".topleftnum, .topright").css("z-index", 0);
    })

    function toggleAdversaryView() {
        // Change Add/View sidebar
        $('#adversary-view').toggle();
        $('#adversary-add').toggle();

        // Clear content if switching to "Add"
        if ($('#adversary-add').is(':visible')) {
            clearAdversaryContent();
        }

        // Set content visibility and sidebar buttons enable
        checkAdversaryContent();
        checkAdversaryButtons();
    }

    function checkAdversaryContent() {
        if ($('#adversary-add').is(':visible') || $('#profile-existing-name').val() !== null) {
            $('#adversary-content').css('visibility', 'visible');
        } else {
            $('#adversary-content').css('visibility', 'hidden');
        }
    }

    function checkAdversaryButtons() {
        validateFormState(($('#profile-goal').val() !== '' && $('#profile-description').val() !== ''), '#adversary-save-button');
        validateFormState(($('#profile-existing-name').val()), '#adversary-delete-button');
    }

    function clearAdversaryContent() {
      $('#profile-existing-name option:eq(0)').prop('selected', true);
      $('#profile-goal').val('');
      $('#profile-description').val('');
      $('.tempPhase').remove();
      $('.phase-headers').remove();
      loadAtomicOrder([]);
      clearObjective();
    }

    function saveAdversary() {
        let identifier = $('#profile-existing-name').val();
        if(!identifier){
            identifier = uuidv4();
        }
        let name = $('#profile-goal').val();
        if(!name){ warn('Please enter a profile name!'); return; }
        let description = $('#profile-description').val();
        if(!description){ warn('Please enter a description!'); return; }

        let objective = $('#objective-select').val();
        let abilities = [];
        let listing = g_grid.getItems();
        listing.forEach(function(entry){
            abilities.push({"id": entry._element.id})});
        restRequest('PUT', {"name":name,"description":description,"atomic_ordering":abilities,"index":"adversaries",
            'id': identifier,"objective":objective}, saveAdversaryCallback);
    }

    function saveAdversaryCallback(data) {
        stream('Adversary saved!');
        appendToSelect('profile-existing-name', data[0].adversary_id, data[0].name, 'adversary-'+data[0].adversary_id);
        $('#profile-existing-name').val(data[0].adversary_id);
        appendToSelect('queueFlow', data[0].adversary_id, data[0].name, 'qflow-'+data[0].adversary_id);

        if ($('#adversary-add').is(':visible')) {
          $('#togBtnAdv').click();
        }
    }

    function checkAbilityButtons() {
        // Enable / Disable Save and Add to Adversary buttons
        let valid = validateAbility();
        let uniqueAbility = ($('#ability-identifier').val() === "" ||
                             $('#tempPhase1').find('#' + $('#ability-identifier').val()).length === 0);
        validateFormState(valid, '#ability-save');
        validateFormState((valid && uniqueAbility), '#ability-add-to-adv');
    }

    function validateAbility() {
        // Enable Save and Add to Adversary buttons if the ability has:
        // - No ID, or ID only contains valid characters
        // - Name
        // - Description
        // - Tactic is not empty and only contains valid characters
        // - Platform / executor / command
        // - Unique, non-empty keys in additional info
        let valid = true;
        let validator = /^[0-9a-z-_]+$/i;

        // Validate ID
        let abilityId = $('#ability-identifier').val();
        if (abilityId.length !== 0 && !(validator.test(abilityId))) {
            valid = false;
        }

        // Ability details missing data
        if (valid) {
            if (
                $('#ability-name').val().length === 0
                || $('#ability-description').val().length === 0
            ) {
                valid = false;
            }
        }

        // Validate tactic
        if (valid) {
            let abilityTactic = $('#ability-tactic-name').val();
            if (abilityTactic.length !== 0 && !(validator.test(abilityTactic))) {
                valid = false;
            }
        }

        // Platform / executor / command missing data
        if (valid) {
            if ($('#ttp-tests > li').length) {
                $('#ttp-tests > li').each(function() {
                    let platform = $(this).find('#ability-platform').val();
                    let executor = $(this).find('#ability-executor').val();
                    let command = $(this).find('#ability-command').val();
                    if (!command || !executor || !platform) {
                        valid = false;
                    }
                });
            } else {
                valid = false;
            }
        }

        // Additional info missing data
        if (valid) {
            let additionalInfo = {};
            $('#ability-additional-info').find('#additional-info-table tr').each(function() {
                let key = $(this).find('.additional-key').val();
                if (key !== '' && !(key in additionalInfo)) {
                    additionalInfo[key] = $(this).find('.additional-value').val();
                } else {
                    valid = false;
                }
            });
        }

        return valid;
    }

    function saveAbility(addToAdversary=false) {
        if (!validateAbility()) {
            warn('Missing required data!');
            stream('Missing required data!');
            return;
        }

        let data = {};
        let platforms = {};

        let name = $('#ability-name').val();
        let description = $('#ability-description').val();

        $('#ttp-tests > li').each(function() {
            let platform = $(this).find('#ability-platform').val();

            if (platforms[platform] === undefined) {
                platforms[platform] = {};
            }

            let executor = $(this).find('#ability-executor').val();
            let command = $(this).find('#ability-command').val();
            let payloads = $(this).find('#ability-payload').val();
            let cleanup = $(this).find('#ability-cleanup').val();
            let timeout = $(this).find('#ability-timeout').val();

            let ex = {'command': command};
            if (payloads) {
                ex['payloads'] = payloads;
            }
            if (cleanup) {
                ex['cleanup'] = cleanup;
            }
            if (timeout) {
                ex['timeout'] = parseInt(timeout);
            }
            platforms[platform][executor] = ex;
        });
        $('#ability-additional-info').find('#additional-info-table tr').each(function() {
            let key = $(this).find('.additional-key').val();
            if (key !== '' && !(key in data)) {
                data[key] = $(this).find('.additional-value').val();
            }
        });
        data['index'] = 'abilities';
        data['id'] = $('#ability-identifier').val();
        data['name'] = name;
        data['description'] = description;
        data['tactic'] = $('#ability-tactic-name').val();
        data['technique'] = {'attack_id': $('#ability-tech-id').val(), 'name': $('#ability-tech-name').val()};
        data['platforms'] = platforms;

        $.ajax({
           url: '/api/rest',
           type: 'PUT',
           contentType: 'application/json',
           data: JSON.stringify(data),
           success: function(data, status, options) {
               saveAbilityCallback(data, addToAdversary);
           },
           error: function (xhr, ajaxOptions, thrownError) {
               stream(thrownError);
           }
        });
    }

    function saveAbilityCallback(data, addToAdversary=false) {
        if ($('#ability-identifier').val() === '') {
            $('#ability-identifier').val(data[0].ability_id);
        }
        let abilitySelector = $('#phase-modal').find('#ability-ability-filter');
        let selectedAbility = abilitySelector.find(':selected').data('ability');

        let newAbility = data[0];

        if (!selectedAbility || selectedAbility.ability_id != newAbility.ability_id) {
            appendAbilityToList('phase-modal', newAbility);
        } else {
            abilitySelector.find(':selected')
                .attr('value', newAbility.name)
                .data('ability', newAbility)
                .text(newAbility.name);
        }
        abilitySelector.val(newAbility.name);

        var $to_replace = -1;
        $.each(exploits, function(i, ab) {
            if (ab.ability_id === newAbility.ability_id) {
                $to_replace = i;
                return false;
            }
        });
        if ($to_replace != -1) {
            exploits[$to_replace] = newAbility;
        } else {
            exploits.push(newAbility);
        }
        stream('Ability saved!');

        let tactics = $.map($('#ability-tactic-filter option'), function(option) {
            if (option.value) {
                return option.value;
            }
        });
        if ($.inArray(newAbility.tactic, tactics) === -1) {
            var newTactic = $('<option></option>')
                .attr('value', newAbility.tactic)
                .attr('data-tactic', newAbility.tactic)
                .text(newAbility.tactic);
            $('#ability-tactic-filter').append(newTactic);
        }

        if (addToAdversary) {
            addAbilityToAdversary();
        } else {
            replaceAbilityInAdversary();
        }
    }

    function replaceAbilityInAdversary() {
        let ability = $('#phase-modal').find('#ability-ability-filter').find(':selected').data('ability');
        let abilityItem = $(g_grid.getElement()).children('#' + ability.ability_id);
        if (abilityItem.length) {
            let abilityIndex = parseInt($(abilityItem).find('.ability-order').text()) - 1;
            g_grid.remove(g_grid.getItems(abilityIndex), { removeElements: true });
            let abilityBox = buildAbility(ability);
            g_grid.add(abilityBox[0], { index: abilityIndex });
        }
    }

    function addAbilityToAdversary() {
        let ability = $('#phase-modal').find('#ability-ability-filter').find(':selected').data('ability');
        let abilityBox = buildAbility(ability);
        g_grid.add(abilityBox[0]);
        clearPhaseModal();
        hidePhaseModal();
    }

    function appendToSelect(field, identifier, value, optionId) {
        let exists = false;
        $('#'+field+' option').each(function(){
            if (this.value === identifier) {
                exists = true;
                return false;
            }
        });
        if(!exists) {
            $("#"+field).append($("<option></option>")
                .attr("id", optionId)
                .attr("value", identifier)
                .text(value));
        }
    }

    function loadAdversary() {
        restRequest('POST', {'index':'adversaries', 'adversary_id': $('#profile-existing-name').val()}, loadAdversaryCallback);
    }

    function loadAdversaryCallback(data) {
        stream('Profiles contain abilities which will run in atomic order by default. It contains abilities, or TTPs.');

        $('#adversary-content').css('visibility', 'visible');
        $('#profile-goal').val(data[0].name);
        $('#profile-description').val(data[0].description);

        $('.tempPhase').remove();
        $('.phase-headers').remove();
        loadAtomicOrder(data[0].atomic_ordering);
        $('#objective-existing')[0].value = data[0].objective.id;
        handleObjectiveSelection(data[0].objective.id);
        linkObjective();

        checkAdversaryButtons();
    }

    function createMuuriGrid() {
        let packer = new Muuri.Packer();
        return new Muuri('.grid', {
            dragEnabled: true,
            layout: function (items, width, height) {
            let fakeItems = items.map(item => {
              return {
                _width: Math.floor(item._width + item._marginLeft + item._marginRight),
                _height: Math.floor(item._height + item._marginTop + item._marginBottom),
                _marginLeft: 0,
                _marginRight: 0,
                _marginTop: 0,
                _marginBottom: 0
              }
            });
            let slots = [];
            let options = {rounding: false};
            return packer.getLayout(fakeItems, width, height, slots, options);}
        });
    }

    function loadAtomicOrder(abilities) {
        let template = $("#tempPhase");
        if (!template.length) {
            template = addPhase(1);
        }
        let grid = createMuuriGrid();
        abilities.forEach(function(a) {
            let abilityBox = buildAbility(a);
            grid.add(abilityBox[0]);
        });
        g_grid = grid;
        g_grid.on('move', updateIndices).on('add', updateIndices).on('remove',updateIndices);
        updateIndices();
    }

    function updateIndices() {
        g_grid.getItems().forEach(function (item, i) {
          var newId = i + 1;
          item.getElement().setAttribute('data-id', newId);
          item.getElement().querySelector('.ability-order').innerHTML = newId;
          if (item._dragPlaceholder.isActive()) {
            item._dragPlaceholder._element.querySelector('.ability-order').innerHTML = newId;
          }
        });
    }

    function addPhase(number) {
        stream('Add abilities by selecting +add abilities. You can even create new abilities');
        let template = $("#phase-template").clone();
        if(number == null) {
            let existingPhases = $('.tempPhase').length;
            number = existingPhases + 1;
        }
        template.attr("id", "tempPhase" + number);
        template.addClass("tempPhase");
        if(number == 1) {
            template.insertBefore('#dummy');
        } else {
            template.insertAfter('#tempPhase' + (number-1));
        }
        template.show();
        let phaseHeader = $('<h4 class="phase-headers"><span class="phase-title">Ordering</span>' +
            '<span class="ability-add" onclick="showPhaseModal('+number+'); checkAbilityButtons()">&#10010; add ability</span>'
            +'<span class="ability-add" onclick="showProfileModal('+number+')" ' +
            'style="margin-right:5px;padding-right:5px;border-right:1px white solid;">&#10010; add adversary</span>' +
            '<span class="ability-add" onclick="showObjectiveModal()" ' +
            'style="margin-right:5px;padding-right:5px;border-right:1px white solid;">&#10010; link objective</span>' +
            '<hr></h4>');
        $('#tempPhase' + number).prepend(phaseHeader);
        phaseHeader.show();
        return template;
    }

    function buildAbility(ability) {
        let abilityRequirements = [];
        let cleanupCommands = false;
        let parsers = false;
        let payloads = false;

        let template = $('#ability-template').clone();
        template.attr('id', ability.ability_id)
            .data('abilityId', ability.ability_id)
            .data('requirements', abilityRequirements);
        template.find('#name span').html(ability.name);
        template.find('#ability-attack').html(ability.tactic + ' | '+ ability.technique_name);

        ability.executors.forEach((executor) => {
            if (executor.command !== null) {
                let executorRequirements = buildRequirements(executor.command);
                abilityRequirements = abilityRequirements.concat(executorRequirements);
            }

            cleanupCommands = (cleanupCommands || executor.cleanup.length > 0);
            parsers = (parsers || executor.parsers.length > 0);
            payloads = (payloads || executor.payloads.length > 0);

            let executorNames = new Map([
              ['psh', 'powershell'],
              ['pwsh', 'powershell core'],
              ['sh', 'shell'],
              ['cmd', 'commandline'],
            ]);
            let executorName = executorNames.get(executor.name) || executor.name;

            $('<div></div>')
                .addClass('tooltip')
                .attr('data-text', 'Works on ' + executor.platform + ' (' + executorName + ')')
                .append($('<img/>').attr('src', '/gui/img/' + executor.platform + '.png'))
                .appendTo(template.find('#icon-row'));
        });

        if (abilityRequirements.length > 0) {
            template.find('#ability-metadata').append('<div id="ability-padlock" style="padding: 0 2;"><div class="tooltip" data-text="This ability has requirements">&#128274;</div></div>');
        }
        if (cleanupCommands) {
            template.find('#ability-metadata').append('<div id="ability-broom" style="padding: 0 2;"><div class="tooltip" data-text="This ability can clean itself up">&#128465;</div></div>');
        }
        if (parsers) {
           template.find('#ability-metadata').append('<div id="ability-parser" style="padding: 0 2;"><div class="tooltip" data-text="This ability unlocks other abilities">&#128273;</div></div>');
        }
        if (payloads) {
           template.find('#ability-metadata').append('<div id="ability-payload" style="padding: 0 2;"><div class="tooltip" data-text="This ability uses a payload">&#128176;</div></div>');
        }

        template.find('#ability-rm').html('<div class="ability-remove"><div style="font-size:8px;">&#x274C;</div></div>');
        template.find('.ability-remove').click(function() {
            removeAbility(ability);
        });

        template.find('.ability-show').click(function() {
            let pModal = $('#phase-modal');
            let tacList = pModal.find('#ability-tactic-filter');
            let techList = pModal.find('#ability-technique-filter');
            let abList = pModal.find('#ability-ability-filter');
            tacList.val(ability['tactic']).change();
            techList.val(ability['technique_id']).change();
            abList.val(ability['name']).change();
            showPhaseModal(1);
        });
        template.show();
        return template;
    }

    function buildRequirements(command) {
        let matchedRequirements = command.match(/#{([^}]+)}/g);
        if (matchedRequirements) {
            matchedRequirements = matchedRequirements.filter(function(e) { return e !== '#{server}' });
            matchedRequirements = matchedRequirements.filter(function(e) { return e !== '#{group}' });
            matchedRequirements = matchedRequirements.filter(function(e) { return e !== '#{location}' });
            matchedRequirements = matchedRequirements.filter(function(e) { return e !== '#{paw}' });
            return matchedRequirements.map(function(val){
               return val.replace(/[#{}]/g, "");
            });
        }
        return [];
    }

    function removeAbility(ability){
        let listing = g_grid.getItems();
        listing.forEach(function(entry) {
            if (entry._element.id === ability.ability_id) {
                g_grid.remove(g_grid.getItems().indexOf(entry), {removeElements: true});
            }
        });
    }

    function showAbility(parentId, exploits) {
        $('#ability-name').val('');
        $('#ability-description').val('');
        $('#ttp-tests').empty();
        $('#ability-additional-info').find('#additional-info-table').empty();
        $('#ability-additional-info').hide();

        let ability = $('#'+parentId).find('#ability-ability-filter').find(':selected').data('ability');
        $('#ability-identifier').val(ability.ability_id);
        $('#ability-name').val(ability.name);
        $('#ability-description').val(ability.description);
        $('#ability-tactic-name').val(ability.tactic);
        $('#ability-tech-id').val(ability.technique_id);
        $('#ability-tech-name').val(ability.technique_name);

        if (Object.keys(ability.additional_info).length > 0) {
            ability.additional_info.forEach((value, key) => {
                let $table_row = addAdditionalInfo();
                $table_row.find('.additional-key').val(key);
                $table_row.find('.additional-value').val(value);
            });
            $('#ability-additional-info').show();
        }

        ability.executors.forEach((executor) => {
            let template = $('#ttp-template').clone();
            let unique = ability.ability_id + executor.platform + executor.name;
            template.attr('id', unique);
            template.find('#ability-platform').val(executor.platform);
            filterExecutors(template.find('#ability-platform'));
            template.find('#ability-executor').val(executor.name);
            template.find('#ability-command').val(executor.command);
            template.find('#ability-timeout').val(ability.timeout);
            if (executor.cleanup.length > 0) {
                template.find('#ability-cleanup').val(executor.cleanup[0]);
            }
            template.show();

            $('#ttp-tests').append(template);
            let payloads = $('#'+unique).find('#ability-payload');
            payloads.multiSelect({
                selectableHeader: "<div class='payload-select-header'>Available Payloads</div>",
                selectionHeader: "<div class='payload-select-header'>Selected Payloads</div>",
                keepOrder: true });
            payloads.multiSelect('select', executor.payloads);
        });

        checkAbilityButtons();
    }

    function filterExecutors(elem) {
        let ttpTable = $(elem).closest('table');
        let platform = $(elem).val();
        let executorSelect = $(ttpTable).find('#ability-executor');
        $(executorSelect).empty();
        $(executorSelect).append($('<option></option>')
            .text('Select an executor')
            .attr('disabled', 'disabled')
            .attr('selected', 'selected'));

        platforms[platform].forEach((executor) => {
            $(executorSelect).append($('<option></option>')
                .val(executor)
                .text(executor));
        });
    }

    function addExecutorBlock(){
        let template = $("#ttp-template").clone();
        template.show();
        $('#ttp-tests').prepend(template);
        $('#ttp-tests').find('#ability-payload').multiSelect({
            selectableHeader: "<div class='payload-select-header'>Available Payloads</div>",
            selectionHeader: "<div class='payload-select-header'>Selected Payloads</div>",
            keepOrder: true });
    }

    function addAdditionalInfo(){
        let $table_row = $('#additional-info-row-template-holder').find('#additional-info-template').clone();
        $('#ability-additional-info').find('#additional-info-table').append($table_row);
        $('#ability-additional-info').show();
        $table_row.find('.ability-remove').click(function(){
            if ($('#additional-info-table tr').length == 1){
                $('#ability-additional-info').hide();
            }
            $(this).parent().parent().remove();
            checkAbilityButtons();
        });
        return $table_row;
    }

    function showPhaseModal(phase) {
        $('#phase-modal').data("phase", phase);
        $('#ability-identifier').text(uuidv4());
        $('body').keyup(function(e){
            if(e.key == "Escape"){
                hidePhaseModal();
            }
        });
        document.getElementById("phase-modal").style.display="block";
    }

    function hidePhaseModal() {
        $('#phase-modal').hide();
        $('#ability-search-filter').val('');
    }

    function clearPhaseModal() {
        $('#ability-tactic-filter option:first').prop('selected', true);
        $('#ability-technique-filter').empty().append('<option disabled="disabled" selected>Choose a technique</option>');
        $('#ability-ability-filter').empty().append('<option disabled="disabled" selected>0 abilities</option>');
        $('#ability-identifier').val('');
        $('#ability-name').val('');
        $('#ability-description').val('');
        $('#ability-tactic-name').val('');
        $('#ability-tech-id').val('');
        $('#ability-tech-name').val('');
        $('#ttp-tests').empty();
    }

    function showProfileModal(phase) {
        $('#adv-profile-modal').data("phase", phase);
        $('body').keyup(function(e){
            if(e.key == "Escape"){
                hideProfileModal();
            }
        });
        document.getElementById("adv-profile-modal").style.display="block";
    }

    function showObjectiveModal() {
        $('body').keyup(function(e){
            if(e.key == "Escape"){
                hideObjectiveModal();
            }
        });
        document.getElementById("adv-objective-modal").style.display="block";
    }

    function hideProfileModal() {
        $("body").off("keyup");
        document.getElementById("adv-profile-modal").style.display="none";
    }

    function hideObjectiveModal(){
        $("body").off("keyup");
        document.getElementById("adv-objective-modal").style.display="none";
    }

    function freshId(){
        $('#ability-identifier').val(uuidv4());
        checkAbilityButtons();
    }

    function uploadPayload() {
        let file = document.getElementById('uploadPayloadFile').files[0];
        let fd = new FormData();
        fd.append('file', file);
        $.ajax({
             type: 'POST',
             url: '/file/upload',
             beforeSend: function(xhr){xhr.setRequestHeader('Directory', 'data/payloads/');},
             data: fd,
             processData: false,
             contentType: false
        }).done(function (){
            let exists = $("#ability-payload option").filter(function (i, o) { return o.value === file.name; }).length > 0;
            if(!exists) {
                $('.ability-payload').each(function(i, obj) {
                    $(this).append(new Option(file.name, file.name));
                });
            }
        })
    }
    $('#uploadPayloadFile').on('change', function (event){
        if(event.currentTarget) {
            let filename = event.currentTarget.files[0].name;
            if(filename){
                uploadPayload();
            }
        }
    });

    $('#objective-existing').on('change', function (){
        handleObjectiveSelection($('#objective-existing').val());
    });

    function handleObjectiveSelection(id) {
       restRequest('POST', {'index':'objectives', 'id': id}, requestObjectiveCallback);
    }

    function requestObjectiveCallback(data){
        $('#objective-description')[0].value = data[0]['description'];
    }

    function linkObjective() {
        $('#objective-select')[0].value = $('#objective-existing').val();
        $('#objective-img')[0].style="";
    }

    function clearObjective() {
        $('#objective-select')[0].value = '';
        $('#objective-img')[0].style="display:none";
    }

    function deleteProfile(){
        function deleteCallback(data){
            $('#adversary-' + adversary_id).remove();
            clearAdversaryContent();
            checkAdversaryContent();
            checkAdversaryButtons();
            stream(data);
        }
        let adversary_id = $('#profile-existing-name').val();
        if (confirm(`Are you sure you want to terminate this adversary?`)){
            restRequest('DELETE', {"index": "adversaries", "adversary_id": adversary_id}, deleteCallback);
        }
    }

    function addAdvToCurrentProfile() {
        function loadAdvProfileCallback(data) {
            data[0]['atomic_ordering'].forEach((ability) => {
                let abilityBox = buildAbility(ability);
                g_grid.add(abilityBox[0]);
            });
        }
        restRequest('POST', {'index':'adversaries', 'adversary_id': $('#adv-profile-filter').val()}, loadAdvProfileCallback);
        hideProfileModal();
    }

    //# sourceURL=profiles.js

    function isEllipsisActive(e) {
        return (e.offsetWidth < e.scrollWidth);
    }

</script>
